package com.edais.mina.codec;

import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;
import org.apache.mina.filter.codec.demux.MessageEncoder;

import java.util.concurrent.ConcurrentHashMap;

public class DefaultCodec extends Codec {
	private String sendCharset = "UTF-8";
	// private String recCharset = "GBK";
	private String recCharset = "UTF-8";

	private static final Logger logger = Logger.getLogger(DefaultCodec.class);

	public DefaultCodec() {
		super();
	}

	public ProtocolCodecFilter getCodecFilter() {
		DemuxingProtocolCodecFactory pcf = new DemuxingProtocolCodecFactory();
		pcf.addMessageEncoder(String.class, new DefaultEncoder());// 编码器
		pcf.addMessageDecoder(new DefaultDecoder());// 解码器
		ProtocolCodecFilter codec = new ProtocolCodecFilter(pcf);
		return codec;
	}

	class DefaultEncoder implements MessageEncoder {
		public void encode(IoSession session, Object message,
						   ProtocolEncoderOutput out) throws Exception {
			byte[] bytes = message.toString().getBytes("UTF-8");
			IoBuffer buffers = IoBuffer
					.allocate(bytes.length);
			buffers.put(bytes);
			buffers.flip();

			out.write(buffers);
		}
	}

	class DefaultDecoder implements MessageDecoder {
		private ConcurrentHashMap<Long, Integer> map = new ConcurrentHashMap<Long, Integer>();
		private ConcurrentHashMap<Long, Integer> map_size = new ConcurrentHashMap<Long, Integer>();
		private ConcurrentHashMap<Long, byte[]> map_buffer = new ConcurrentHashMap<Long, byte[]>();

		public MessageDecoderResult decodable(IoSession arg0, IoBuffer arg1) {
			if (arg1.remaining() <= 0) {
				return MessageDecoderResult.NOT_OK;
			}
			return MessageDecoderResult.OK;
		}

		public MessageDecoderResult decode(IoSession session, IoBuffer buffer,
										   ProtocolDecoderOutput out) throws Exception {
			byte[] b = new byte[buffer.limit()];
			buffer.get(b);
			int length;

			if (map.get(session.getId()) == null) {
				byte[] len = new byte[8];
				System.arraycopy(b, 0, len, 0, 8);
				String lenStr = new String(len);

				length = Integer.parseInt(lenStr);
				map.put(session.getId(), length);
			} else {
				length = map.get(session.getId());
			}

			int size = buffer.limit();
			if (map_size.get(session.getId()) == null) {
				map_size.put(session.getId(), size);
			} else {
				size = buffer.limit() + map_size.get(session.getId());
				map_size.put(session.getId(), size);
			}

			byte[] bb = new byte[buffer.limit()];
			System.arraycopy(b, 0, bb, 0, bb.length);

			if (map_buffer.get(session.getId()) == null) {
				map_buffer.put(session.getId(), bb);
			} else {
				byte[] old = map_buffer.get(session.getId());
				byte[] data = new byte[old.length + bb.length];
				System.arraycopy(old, 0, data, 0, old.length);
				System.arraycopy(bb, 0, data, old.length, bb.length);
				map_buffer.put(session.getId(), data);
			}

			if (length > size) {
				return MessageDecoderResult.NEED_DATA;
			} else {

			}

			out.write(new String(map_buffer.get(session.getId()), recCharset));
			buffer.free();

			map.remove(session.getId());
			map_size.remove(session.getId());
			map_buffer.remove(session.getId());

			return MessageDecoderResult.OK;
		}

		public void finishDecode(IoSession iosession,
								 ProtocolDecoderOutput protocoldecoderoutput) throws Exception {
		}

	}

}
